﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using NLite.Reflection;
using NLite.Collections;
using System.Diagnostics;
using NLite.Validation;

namespace NLite.Mapping.Internal
{
    sealed class ClassMapper : MapperBase
    {
        public ClassMapper(Type fromType, Type toType)
            : base(fromType, toType)
        {
        }

        public override void Map(ref object from, ref object to)
        {
            var mappings = _Info.Mappings.Value;
            var mappingCount = mappings.Count;

            if (_Info.memberMappings.Count == 0 && mappingCount == 0)
                return;

            if(to == null)
                to = ObjectCreator.Create(_Info.To);

            for(int i=0;i<mappingCount;i++)
            {
                
                var item = mappings[i];
                try
                {
                    object value = GetSourceMemberValue(ref from, ref item);

                    var key = item.From.Type.FullName + "->" + item.To.Type.FullName;
                    if (_Info.CanUsingConverter(key))
                        value = _Info.converters[key].DynamicInvoke(value);
                    else
                        value = Mapper.Map(value, item.From.Type, item.To.Type);

                    item.To.SetMember(to, value);
                }
                catch (Exception ex)
                {
                    State.AddError( string.Format("{0}.{1} -> {2}.{3}"
                        , item.From.Member.DeclaringType.Name
                        , item.From.Name
                        , item.To.Member.DeclaringType.Name
                        , item.To.Name), ex.Message);
                }
            }

            FilterMembers(ref from, ref to);
        }

        internal object GetSourceMemberValue(ref object from, ref MemberMapping item)
        {
            var value = item.From.GetMember(from);

            if (!string.IsNullOrEmpty(item.FromMemberPath) && value != null)
            {
                var members = item.FromMemberPath.Split('.').ToList();
                members.RemoveAt(0);

                for (int i = 0; i < members.Count; i++)
                {
                    var f = value.GetType().GetMember(members[i]).FirstOrDefault();
                    if (f != null)
                        value = f.Get(value); 
                }
            }


            return value;
        }


    }

    
}
